/***
 This is free and unencumbered software released into the public domain.

 Anyone is free to copy, modify, publish, use, compile, sell, or
 distribute this software, either in source code form or as a compiled
 binary, for any purpose, commercial or non-commercial, and by any
 means.

 For more information, please refer to <http://unlicense.org/>
 */

package com.htfyun.serialport.utils;

import android.os.Environment;
import android.util.Log;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;


/**
 * @author Mustafa Ferhan Akman
 *         <p>
 *         Create a simple and more understandable Android logs.
 * @date 21.06.2012
 */

public class SerialDebugLog {

    static String className;
    static String methodName;
    static int lineNumber;
    static final String TAG = "serial_port";
    private final static boolean SAVE_DEBUG = true;

    private static boolean debuggable = false;

    private SerialDebugLog() {
        /* Protect from instantiations */
    }

    public static boolean isDebuggable() {
        if (!debuggable) {
            FileUtils.deleteDir(DEBUG_DIR);
        }
        return debuggable;
    }

    public static void setDebuggable(boolean dbg) {
        debuggable = dbg;
    }

    private static String createLog(String log) {

        StringBuffer buffer = new StringBuffer();
        buffer.append("[" + className);
        buffer.append(methodName);
        buffer.append(":");
        buffer.append(lineNumber);
        buffer.append("]");
        buffer.append(log);

        return buffer.toString();
    }

    private static void getMethodNames(StackTraceElement[] sElements) {
        className = sElements[1].getFileName().replace("java", "");
        methodName = sElements[1].getMethodName();
        lineNumber = sElements[1].getLineNumber();
    }

    public static void e(String message) {
//        System.out.println(message);
        if (!isDebuggable())
            return;

        // Throwable instance must be created before any methods
        getMethodNames(new Throwable().getStackTrace());
        String log = createLog(message);

        if (SAVE_DEBUG) {
            save("Log.e : " + log);
        } else {
            Log.e(TAG, log);
        }

    }

    public static void i(String message) {
        if (!isDebuggable())
            return;

        getMethodNames(new Throwable().getStackTrace());
        Log.i(TAG, createLog(message));

        save("Log.i : " + createLog(message));

    }

    public static void d(String message) {
        if (!isDebuggable())
            return;

        getMethodNames(new Throwable().getStackTrace());
        Log.d(TAG, createLog(message));
        save("Log.d : " + createLog(message));

    }

    public static void v(String message) {
        if (!isDebuggable())
            return;

        getMethodNames(new Throwable().getStackTrace());
        Log.v(TAG, createLog(message));

        save("Log.v : " + createLog(message));

    }

    public static void w(String message) {
        if (!isDebuggable())
            return;

        getMethodNames(new Throwable().getStackTrace());
        Log.w(TAG, createLog(message));
        save("Log.w : " + createLog(message));

    }


    public static void wtf(String message) {
        if (!isDebuggable())
            return;

        getMethodNames(new Throwable().getStackTrace());
        Log.wtf(TAG, createLog(message));

        save("Log.wtf : " + createLog(message));

    }

    private final static String DEBUG_DIR = Environment.getExternalStorageDirectory().toString()
            + File.separator + "serialLog";


    public static String getDebugDir() {
        File file_dir = new File(DEBUG_DIR);
        if (!(file_dir.exists())) {
            file_dir.mkdirs();
        }

        return file_dir.getAbsolutePath();
    }

    private static String getFileName() {

        return getDebugDir() + File.separator + now2String() + ".log";

    }

    private static String fileName = null;

    private static void save(String string) {

        if (SAVE_DEBUG) {
            if (fileName == null) {
                checkAndDeleteFiles();
                fileName = getFileName();
            }

            checkFileLengthAndDeleteFile(new File(fileName));

            String appendString = now2String() + " : " + string + "\n";

            UsefulUtil.writeAppendFile(fileName, appendString);

        }

    }

    private static final long MAX_FILE_LENGTH = 50 * 1024 * 1024L;

    private static void checkFileLengthAndDeleteFile(File file) {
        try {
            long fileLength = 0L;
            if(file.exists() && file.isFile()){
              fileLength = file.length();
            }

            if (fileLength > MAX_FILE_LENGTH) {
                file.delete();
            }

        } catch (Exception e) {

        }
    }

    private static void checkAndDeleteFiles() {
        try {
            File debugDir = new File(getDebugDir());
            if (!debugDir.exists()) {
                return;
            }
            final long oneDay_ms = 24 * 3600 * 1000L;
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault());
            String today = format.format(new Date());
            String yesterday = format.format(new Date(System.currentTimeMillis() - oneDay_ms));
            for (File f : debugDir.listFiles()) {
                if (f.getName().contains(today) || f.getName().contains(yesterday)) {
                    checkFileLengthAndDeleteFile(f);
                    continue;
                }
                f.delete();
            }
        } catch (Exception e) {

        }
    }

    private static final ThreadLocal<SimpleDateFormat> SDF_THREAD_LOCAL = new ThreadLocal<>();

    private static SimpleDateFormat getDefaultFormat() {
        SimpleDateFormat simpleDateFormat = SDF_THREAD_LOCAL.get();
        if (simpleDateFormat == null) {
            simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss.SSS", Locale.getDefault());
            SDF_THREAD_LOCAL.set(simpleDateFormat);
        }
        return simpleDateFormat;
    }

    private static String now2String() {
        return getDefaultFormat().format(new Date());
    }


}
